home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockPollerService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
16KB
|
540 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
const PS_CONTRACTID = '@flock.com/poller-service;1';
const PS_CLASSID = Components.ID('{a2b4cd0e-804b-4578-8c3c-4b61f8c1047a}');
const PS_CLASSNAME = 'Flock Poller';
const PREF_POLLER_BRANCH = 'flock.poller'
const PREF_REFRESH_DELAY = '.refreshDelay';
const PREF_REFRESH_TIMEOUT = '.refreshTimeout';
const PREF_DEFAULT_REFRESH_INTERVAL = '.defaultRefreshInterval';
const PREF_MAX_CONCURRENT_REFRESHES = '.maxConcurrentRefreshes';
// According to Mozilla docs, timers can't be set for more than approximately
// 6 hours. We'll limit to 4 hours just to be conservative.
const MAX_TIMER_INTERVAL = 4 * 60 * 60 * 1000;
// Delay actual polling for 30 seconds after component initialization, so
// there is reduced contention among other browser startup operations
const STARTUP_DELAY = 30 * 1000;
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
function getObserverService() {
return Cc['@mozilla.org/observer-service;1']
.getService(Ci.nsIObserverService);
}
function RefreshListener(poller, urn, serviceId) {
this._poller = poller;
this._urn = urn;
this._serviceId = serviceId;
}
RefreshListener.prototype = {
onResult: function PSL_onResult() {
this._poller._logger.info('Successful refresh for ' + this._urn);
this._poller._finishedRefresh(this._urn);
},
onError: function PSL_onError(error) {
this._poller._logger.error('The service ' + this._serviceId + ' returned an ' +
'error while refreshing ' + this._urn);
this._poller._finishedRefresh(this._urn);
},
notify: function PSL_notify(timer) {
this._poller._logger.error('The service ' + this._serviceId + ' timed out ' +
'while refreshing ' + this._urn);
this._poller._finishedRefresh(this._urn);
},
QueryInterface: function PSL_QueryInterface(iid) {
if (iid.equals(Ci.flockIPollerListener) ||
iid.equals(Ci.nsITimerCallback) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
function PollerService() {
var obs = getObserverService();
obs.addObserver(this, 'flock-data-ready', false);
obs.addObserver(this, 'xpcom-shutdown', false);
}
PollerService.prototype = {
_start: function PS__start() {
this._logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
this._logger.init('poller');
this._logger.info('starting up...');
this._profiler = Cc["@flock.com/profiler;1"].getService(Ci.flockIProfiler);
var evtID = this._profiler.profileEventStart('poller-start');
this._timer = Cc['@mozilla.org/timer;1'].createInstance(Ci.nsITimer);
this._coop = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
var prefService = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch2);
prefService.addObserver(PREF_POLLER_BRANCH, this, false);
this.observe(null, 'nsPref:changed', PREF_REFRESH_DELAY);
this.observe(null, 'nsPref:changed', PREF_REFRESH_TIMEOUT);
this.observe(null, 'nsPref:changed', PREF_DEFAULT_REFRESH_INTERVAL);
this.observe(null, 'nsPref:changed', PREF_MAX_CONCURRENT_REFRESHES);
this._initializeQueue();
this._watchRDFEvents();
this._profiler.profileEventEnd(evtID, "");
},
_shutdown: function PS__shutdown() {
var prefService = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefBranch2);
prefService.removeObserver(PREF_POLLER_BRANCH, this);
this._timer.cancel();
this._timer = null;
},
_prefChanged: function PS__prefChanged(pref) {
var prefService = Cc['@mozilla.org/preferences-service;1']
.getService(Ci.nsIPrefService);
var prefBranch = prefService.getBranch(PREF_POLLER_BRANCH);
switch (pref) {
case PREF_REFRESH_DELAY:
this._refreshDelay = prefBranch.getIntPref(pref);
break;
case PREF_REFRESH_TIMEOUT:
this._refreshTimeout = prefBranch.getIntPref(pref);
break;
case PREF_DEFAULT_REFRESH_INTERVAL:
this._defaultRefreshInterval = prefBranch.getIntPref(pref);
break;
case PREF_MAX_CONCURRENT_REFRESHES:
this._maxConcurrentRefreshes = prefBranch.getIntPref(pref);
break;
}
},
_watchRDFEvents: function PS__watchRDFEvents() {
var RDFS = Cc['@mozilla.org/rdf/rdf-service;1']
.getService(Ci.nsIRDFService);
var nextRefresh = RDFS.GetResource('http://flock.com/rdf#nextRefresh');
var isPollable = RDFS.GetResource('http://flock.com/rdf#isPollable');
var faves = Cc['@mozilla.org/rdf/datasource;1?name=flock-favorites']
.getService(Ci.flockIRDFObservable);
faves.addArcObserver(Ci.flockIRDFObserver.TYPE_ALL, null, nextRefresh, null,
this);
faves.addArcObserver(Ci.flockIRDFObserver.TYPE_ALL, null, isPollable, null,
this);
},
rdfChanged: function PS_rdfChanged(ds, type, rsrc, pred, obj, oldObj) {
var pollable = this._coop.get_from_resource(rsrc);
if (pollable && pollable.isPollable) {
if (pollable.nextRefresh)
this._addToQueue(pollable);
else
pollable.nextRefresh = new Date();
} else {
rsrc.QueryInterface(Ci.nsIRDFResource);
this._removeFromQueue(rsrc.ValueUTF8);
}
},
_initializeQueue: function PS__initializeQueue() {
var queue = [];
var dates = {};
var RDFS = Cc['@mozilla.org/rdf/rdf-service;1']
.getService(Ci.nsIRDFService);
var isPollable = RDFS.GetResource('http://flock.com/rdf#isPollable');
var faves = Cc['@mozilla.org/rdf/datasource;1?name=flock-favorites']
.getService(Ci.nsIRDFDataSource);
var pollables = faves.GetSources(isPollable, RDFS.GetLiteral('true'), true);
while (pollables.hasMoreElements()) {
var pollable = this._coop.get_from_resource(pollables.getNext());
var urn = pollable.id();
queue.push(urn);
if (!pollable.nextRefresh)
pollable.nextRefresh = new Date();
dates[urn] = pollable.nextRefresh;
}
function sorter(a, b) {
return dates[a] - dates[b];
}
queue.sort(sorter);
this._queue = queue;
this._dates = dates;
this._refreshing = {};
this._refreshOrder = [];
this._lastRefresh = new Date(0);
this._logger.debug('queue initialized: ' + this._queue.toSource());
this._initTimer(STARTUP_DELAY);
},
_addToQueue: function PS__addToQueue(obj) {
var urn = obj.id();
var nextRefresh = obj.nextRefresh;
var date = this._dates[urn];
if (date) {
if (date - nextRefresh == 0)
return;
else
this._queue.splice(this._queue.indexOf(urn), 1);
}
this._dates[urn] = nextRefresh;
for (var i = 0; i < this._queue.length; i++) {
var date = this._dates[this._queue[i]];
if (nextRefresh < date) {
this._queue.splice(i, 0, urn);
if (i == 0)
this._recalculateTimer();
this._logger.debug('queue updated: ' + this._queue.toSource());
return;
}
}
this._queue.push(urn);
if (this._queue.length == 1)
this._recalculateTimer();
this._logger.debug('queue updated: ' + this._queue.toSource());
},
_removeFromQueue: function PS__removeFromQueue(urn) {
var date = this._dates[urn];
if (!date)
return;
delete this._dates[urn];
var index = this._queue.indexOf(urn);
if (index == 0) {
this._queue.shift();
this._recalculateTimer();
} else {
this._queue.splice(index, 1);
}
this._logger.debug('queue updated: ' + this._queue.toSource());
},
_initTimer: function PS__initTimer(interval) {
this._logger.debug('next refresh: ' + interval / 1000);
this._timer.initWithCallback(this, interval, Ci.nsITimer.TYPE_ONE_SHOT);
},
_recalculateTimer: function PS__recalculateTimer() {
this._timer.cancel();
if (this._queue.length) {
var date = this._dates[this._queue[0]];
var now = new Date();
var interval = date > now ? date - now : 0;
interval = Math.min(interval, MAX_TIMER_INTERVAL);
if (this._refreshOrder.length) {
var urn = this._refreshOrder[this._refreshOrder.length - 1];
var start = this._refreshing[urn].start;
var delay = (this._refreshDelay * 1000) - (now - start);
interval = Math.max(interval, delay);
if (this._refreshOrder.length > this._maxConcurrentRefreshes - 1) {
urn = this._refreshOrder[0];
start = this._refreshing[urn].start;
delay = (this._refreshTimeout * 1000) - (now - start);
interval = Math.max(interval, delay);
}
} else {
var delay = (this._refreshDelay * 1000) - (now - this._lastRefresh);
interval = Math.max(interval, delay);
}
this._initTimer(interval);
}
},
_finishedRefresh: function PS__finishedRefresh(urn) {
var index = this._refreshOrder.indexOf(urn);
if (index == -1)
return;
var refreshInfo = this._refreshing[urn]
if (refreshInfo.timer) {
refreshInfo.timer.cancel();
}
delete this._refreshing[urn];
this._refreshOrder.splice(index, 1);
var obj = this._coop.get(urn);
if (!obj)
return;
obj.isRefreshing = false;
var now = new Date();
if (obj.nextRefresh < now) {
var refreshInterval = obj.refreshInterval ? obj.refreshInterval
: this._defaultRefreshInterval;
obj.nextRefresh = new Date(now.getTime() + refreshInterval * 1000);
}
this._recalculateTimer();
var obs = getObserverService();
obs.notifyObservers(null, "refresh-myworld", null);
},
_refresh: function PS__refresh(obj) {
var urn = obj.id();
if (this._refreshing[urn])
return;
var serviceId = obj.serviceId;
this._logger.debug('serviceId = ' + serviceId);
var service = null;
if (serviceId && Cc[serviceId]) {
try {
service = Cc[serviceId].getService(Ci.flockIPollingService);
}
catch (e) {
this._logger.error('Problem getting "' + serviceId + '" as a ' +
'flockIPollingService, while trying to refresh ' +
urn);
}
}
if (service) {
this._logger.info('Refreshing ' + urn);
try {
var now = new Date();
this._refreshing[urn] = { start: now };
this._refreshOrder.push(urn);
obj.isRefreshing = true;
var listener = new RefreshListener(this, urn, serviceId);
service.refresh(urn, listener);
var refreshInfo = this._refreshing[urn];
if (refreshInfo) {
var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
refreshInfo.timer = timer;
timer.initWithCallback(listener, this._refreshTimeout * 1000,
Ci.nsITimer.TYPE_ONE_SHOT);
}
this._lastRefresh = now;
}
catch (e) {
this._logger.error("Exception while "
+ serviceId
+ " was refreshing a stream: "
+ e);
this._finishedRefresh(urn);
}
} else {
this._logger.error('Problem getting the service, while trying to ' +
'refresh ' + urn);
}
},
notify: function PS_notify(timer) {
var urn = this._queue[0];
var date = this._dates[urn];
var now = new Date();
if (now < date) {
this._recalculateTimer();
return;
}
this._queue.shift();
delete this._dates[urn];
var obj = this._coop.get(urn);
if (obj)
this._refresh(this._coop.get(urn));
else
this._logger.warn('trying to refresh nonexistent object: ' + urn);
this._recalculateTimer();
},
observe: function PS_observe(subject, topic, state) {
var obs = getObserverService();
switch (topic) {
case 'flock-data-ready':
obs.removeObserver(this, 'flock-data-ready');
this._start();
break;
case 'xpcom-shutdown':
obs.removeObserver(this, 'xpcom-shutdown');
this._shutdown();
break;
case 'nsPref:changed':
this._prefChanged(state);
break;
}
},
forceRefresh: function PS_forceRefresh(urn) {
var obj = this._coop.get(urn);
if (!obj)
throw 'URN ' + urn + ' does not exist';
obj.nextRefresh = new Date(0);
},
getInterfaces: function PS_getInterfaces(countRef) {
var interfaces = [Ci.flockIPollerService, Ci.flockIRDFObserver,
Ci.nsITimerCallback, Ci.nsIObserver, Ci.nsIClassInfo,
Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function PS_getHelperForLanguage(language) {
return null;
},
contractID: PS_CONTRACTID,
classDescription: PS_CLASSNAME,
classID: PS_CLASSID,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.SINGLETON,
QueryInterface: function PS_QueryInterface(iid) {
if (iid.equals(Ci.flockIPollerService) ||
iid.equals(Ci.flockIRDFObserver) ||
iid.equals(Ci.nsITimerCallback) ||
iid.equals(Ci.nsIObserver) ||
iid.equals(Ci.nsIClassInfo) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
}
function GenericComponentFactory(ctor) {
this._ctor = ctor;
}
GenericComponentFactory.prototype = {
_ctor: null,
// nsIFactory
createInstance: function(outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return (new this._ctor()).QueryInterface(iid);
},
// nsISupports
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIFactory) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
};
var Module = {
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIModule) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
getClassObject: function(cm, cid, iid) {
if (!iid.equals(Ci.nsIFactory))
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
if (cid.equals(PS_CLASSID))
return new GenericComponentFactory(PollerService);
throw Cr.NS_ERROR_NO_INTERFACE;
},
registerSelf: function(cm, file, location, type) {
var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
cr.registerFactoryLocation(PS_CLASSID, PS_CLASSNAME, PS_CONTRACTID,
file, location, type);
var catman = Cc['@mozilla.org/categorymanager;1']
.getService(Ci.nsICategoryManager);
catman.addCategoryEntry('flock-startup', PS_CLASSNAME,
'service,' + PS_CONTRACTID,
true, true);
},
unregisterSelf: function(cm, location, type) {
var cr = cm.QueryInterface(Ci.nsIComponentRegistrar);
cr.unregisterFactoryLocation(PS_CLASSID, location);
},
canUnload: function(cm) {
return true;
},
};
function NSGetModule(compMgr, fileSpec)
{
return Module;
}